<?php

/***  DOCUMENTATION LAYER

Ceo Framework Kernel Class

Name: CeoKernel
Last Update: Sep 2007
Author: Tom at klenwell@gmail.com

DESCRIPTION
	The kernel class is responsible for handling all the fixed, essential tasks
  that need to be run everytime a Php script is run.  A kernel object is created
  by the Ceo Framework object and the kernel is loaded by the Ceo Framework method,
  load_kernel.

METHODS
	MAGIC
	CeoKernel($debug=0, $oid=null)		*php 4 constructor*
	__construct($debug, $oid)					*php 5 constructor*
	__destruct()	
	
	PUBLIC
  fix_globals()
  fix_magic_quotes()
  normalize_input()
  secure_session()
  security_checks()
  error_handler()
	print_d($message, $color='c33')
	print_r()
	dump()
	
	PRIVATE
  _strip_magic_quotes($Mixed)
  _panic($msg='')
	_set_session_data()
	_get_session_data()
	_has_session_data()
	_set_filename()
	_set_dirpath()
	
USAGE
	$Kernel = new CeoKernel();
	$Kernel->print_r('hello world']);

NOTES
  The kernel is responsible for starting sessions and implementing basic 
  session security precautions
	
	For info on preventing session fixation vulnerabilities, see:
		http://shiflett.org/articles/security-corner-feb2004
		http://www.php.net/manual/en/function.session-regenerate-id.php
		http://www.phpclasses.org/browse/file/12194.html
    
  Also see: 
    http://www.php.net/manual/en/function.session-start.php#72444
    http://www.php.net/manual/en/function.session-name.php#54217
  		
	N.B. : session_regenerate_id() requires PHP 4.3.2+
  	
______________________________________________________________________________*/

// Load File of Base Class
$base_fname = 'base.class.php';
$base_dirpath = dirname(__FILE__) . DIRECTORY_SEPARATOR;
#require_once($base_dirpath . $base_fname);


// Class
/*____________________________________________________________________________*/
class CeoKernel
{
/* PUBLIC PROPERTIES */
var $debug = 0;
var $class_name = __CLASS__;
var $oid = '';
var $DS = DIRECTORY_SEPARATOR;


// public vars
var $globals_on = 0;

/* PRIVATE PROPERTIES */
var $_LOG = array();

var $_filename = '';
var $_dirpath = '';


/* ** MAGIC METHODS ** */
// php4 constructor
function CeoKernel($debug=0, $oid=null)
{
	$this->__construct($debug, $oid);
	register_shutdown_function( array($this, '__destruct') );
}
// END constructor

// php5 constructor
function __construct($debug=0, $oid=null)
{
	// default
	$this->debug = $debug;
	$this->oid = ( empty($oid) ) ? $this->class_name : $oid;
	$this->_set_filename();
	$this->_set_dirpath();
	
	// set error handler
	
	// debug
	if ( $this->debug ) $this->print_d('debugging is active for oid ' . $this->oid);
	if ( $this->debug ) $this->print_d('constructor complete for class ' . __CLASS__);
}
// END constructor

// destructor
function __destruct()
{
	if ( $this->debug ) $this->print_d("destroying class {$this->class_name} (oid: {$this->oid})");
}
// END destructor



/* ** PUBLIC METHODS ** */
// method: globals are bad!
function fix_globals()
{
  $this->globals_on = ( ini_get('register_globals') == 1 ) ? 1 : 0;
  if ( $this->debug ) $this->print_d("globals on: {$this->globals_on}");
  
  // global panic message
  $_html_panic = <<<HTML
  
<h2>php recommends <u>not</u> using globals</h2>
<h4>for information see: <a href="http://php.net/register_globals">php.net</a></h4>
<h4>
  for information on turning off globals see: 
  <a href="http://www.nyphp.org/phundamentals/ini.php">http://www.nyphp.org/phundamentals/ini.php</a>
</h4>

HTML;
	
  // globals on?  everybody panic!
  if ( $this->globals_on ) $this->_panic($_html_panic);
  
  return;
}
// END method


// method: fix magic quotes
function fix_magic_quotes()
{
	set_magic_quotes_runtime(0);
  $this->magic_quotes_on = ( !get_magic_quotes_gpc() ) ? 0 : 1;
  if ( $this->debug ) $this->print_d("magic quotes on -> input will be normalized");
  if ( $this->magic_quotes_on ) $this->normalize_input();
  return;
}
// END method


// method: normalize input
function normalize_input()
{
  // do not call more than once
  static $has_been_called = 0;
  if ( $has_been_called )
  {
    trigger_error('already normalized -- exiting', E_USER_NOTICE);
    return;
  }
  $has_been_called++;
  
  // magic quotes must be on
  if ( !get_magic_quotes_gpc() )
  {
    $this->print_d('magic quotes are off -- will not normalize');
    return;
  }
  
  // strip
  $_GET = $this->_strip_magic_quotes($_GET);
  $_POST = $this->_strip_magic_quotes($_POST);
  $_COOKIE = $this->_strip_magic_quotes($_COOKIE);
  $_REQUEST = array_merge($_GET, $_POST, $_COOKIE);
  #$_FILES = amvc_strip_magic_quotes($_FILES);
  
  return;
}
// END method


// method: open session
function open_session()
{
  // clean up session name (see http://www.php.net/manual/en/function.session-name.php#54217) 
  // suppress error if sn incorrectly named (see http://www.php.net/manual/en/function.session-start.php#72444)
  @$_sn = $this->session_name = session_name();
  if ( isset($_GET[$_sn]) ) { if ( strlen($_GET[$_sn]) != 32 ) unset( $_GET[$_sn] ); }
  if ( isset($_POST[$_sn]) ) { if ( strlen($_POST[$_sn]) != 32 ) unset( $_POST[$_sn] ); }
  if ( isset($_COOKIE[$_sn]) ) { if ( strlen($_COOKIE[$_sn]) != 32 ) unset( $_COOKIE[$_sn] ); }
  if ( isset($PHPSESSID) ) { if ( strlen($PHPSESSID) != 32 ) unset( $PHPSESSID ); }
  
  // start session (it should not have been started yet)
  session_start();
  
  // set session finger print for later integrity check
  $_SESSION['fingerprint'] = $this->get_session_fingerprint(); 
  
  // bug fix (see http://www.php.net/manual/en/function.session-regenerate-id.php#68969)
  // version <= 4.3.3 only
  if ( !version_compare(phpversion(),"4.3.3",">=") ) setcookie( session_name(), session_id(), ini_get("session.cookie_lifetime"), "/" );

	return;
}
// END method


// method: get session fingerprint
function get_session_fingerprint()
{
  $fingerprint = '';
  
  // hard parameters
  $cf_browser = 1;
  $cf_ip_blocks = 0;
  
  // project salt
  $project_salt = ( !empty($PROJECT['name']) ) ? $PROJECT['name'] : $this->_filename;
  
  // browser salt
  $browser_salt = ( $cf_browser ) ? $_SERVER['HTTP_USER_AGENT'] : '';
  
  // ip block salt
  $ip_block_salt = '';
  if ( $cf_ip_blocks )
	{
		$IP_BLOCK = explode('.', $_SERVER['REMOTE_ADDR']);
		foreach ( $IP_BLOCK as $_block ) $ip_block_salt .= $_block;
	}
  
  // build fingerprint
	$fingerprint = md5($project_salt . $browser_salt . $ip_block_salt);
  if ( $this->debug ) $this->print_d('getting session fingerprint: ' . $fingerprint); 
  
  return $fingerprint;
}
// END method

// method: print_d
function print_d($message, $color='#c33')
{
	$out = "<div style='line-height:1.5em; font-family:monospace; color:$color;'>$message</div>";
	echo $out;
	return;
}
// END method

// method: print_r
function print_r($Mixed)
{
	$return = htmlspecialchars(print_r($Mixed, 1));
	$return = "<pre>$return</pre>";
	return $return;
}
// END method

// method: dump
function dump()
{
	echo $this->print_r($this);
	return;
}
// END method



/* ** PRIVATE METHODS ** */
// method: strip magic quotes
function _strip_magic_quotes($Mixed)
{
  if ( is_array($Mixed) ) 
    return array_map(array(&$this, '_strip_magic_quotes'), $Mixed);
  else
    return stripslashes($Mixed);
}
// END method


// method: panic
function _panic($notice='')
{
  if ( $this->debug ) $this->print_d('kernel panic');
  
  if ( empty($notice) ) $notice = 'CEO Framework unable to load';

	$html = <<<HTML
  
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>CEO Framework Kernel Error</title>
</head>
<body>

<!-- kernel panic -->
<div style="margin:10%; color:#993333; font-family:arial,sans-serif; text-align:center;">
$notice
<p style='color:#666;'>site administrators have been notified</p>
<p style="font-size:12px; text-align:right;"><a href="/">home page</a></p>
</div>

</body>
</html>

HTML;
  
  die($html);
}
// END method

// method: _set_session_data
function _set_session_data()
{
	// initialize session
	if ( !session_id() ) session_start(); 
	$_SESSION[$this->oid] = array();
	
	// add session data here
	
	return;
}
// END method

// method: get session data
function _get_session_data()
{
	// initialize session
	if ( !$this->_has_session_data() ) return; 
		
	// retrieve session variables
	// $this->var = $_SESSION[$this->oid]['var'];
	
	return;
}
// END method

// method: has session data
function _has_session_data()
{
	// initialize session
	if ( !session_id() ) session_start(); 
		
	// retrieve session variables
	if ( empty($_SESSION[$this->oid]) ) return 0;
	else return 1;
}
// END method

function _set_filename() { $this->_filename = basename(__FILE__); }
function _set_dirpath() { $this->_dirpath = dirname(__FILE__) . $this->DS; }

} // end class
/*____________________________________________________________________________*/

?>
